using System;
using SQLRunnerLib.Services;
using SQLServices.Log;
using SQLServices.Repository;
using SQLServices.Runners;
using SQLServices.Runners.Events;
using SQLServices.TransMgr;

namespace SQLRunnerLib.TransMgr
{
    /// <summary>
    /// 
    /// </summary>
    internal abstract class AbstractManager : IDisposable, ITransManager
    {

        #region Protected Members

        protected bool _isInTransaction = false;
        protected ISQLDBConn _mainConn;

        #endregion
        #region Constructor

        public AbstractManager(IRunner runner)
        {
            HookEvents(runner);
        }

        #endregion
        #region Hook/Unhook Runner events

        protected void HookEvents(IRunner runner)
        {
            runner.ScriptExecuted += OnScriptExecuted;
            runner.ScriptExecError += OnScriptError;
            runner.ExecutionFinished += OnExecutionFinished;
        }

        protected void UnHookEvents(IRunner runner)
        {
            runner.ScriptExecuted -= OnScriptExecuted;
            runner.ScriptExecError -= OnScriptError;
            runner.ExecutionFinished -= OnExecutionFinished;
        }

        #endregion

        #region Runner Event Handlers

        /// <summary>
        /// When the Runner has finished the execution of all scripts it calls this method.
        /// Each Transaction manager must implement this method.
        /// </summary>
        protected abstract void OnExecutionFinished(object sender, ExecutionFinishedEventArgs e);

        /// <summary>
        /// Called when an exception is returned when a script is executed. Each Transaction 
        /// manager must implement this method
        /// </summary>
        protected abstract void OnScriptError(object sender, ScriptExecutionErrorEventArgs e);

        /// <summary>
        /// Called after a script has been executed. Each transaction manager must implement this
        /// method
        /// </summary>
        protected abstract void OnScriptExecuted(object sender, ScriptExecutedEventArgs e);

        #endregion
        #region ITransManager Implementation

        /// <summary>
        /// Executes the SQL statement for the Runner
        /// </summary>
        public void ExecuteSQL(string sqlStmt)
        {
            DoBeforeExecution();
            _mainConn.Execute(sqlStmt);
            DoAfterExecution();
        }

        /// <summary>
        /// Delegates to the TransManager to gather information in relation
        /// to the exception
        /// </summary>
        /// <param name="exception">Thrown exception running some script</param>
        /// <returns>A message trying to describe the problem</returns>
        public string ParseException(Exception exception)
        {
            return _mainConn.ParseException(exception);
        }

        /// <summary>
        /// Hook into the execution process that runs before the execution takes place
        /// </summary>
        protected abstract void DoAfterExecution();

        /// <summary>
        /// Hook into the execution process that runs just after the execution of the script
        /// </summary>
        protected abstract void DoBeforeExecution();

        #endregion
        #region IDispose Implementation
        
        public void Dispose()
        {
            CleanConnection();
        }

        #endregion
        #region Clean Connection

        protected void CleanConnection(ref ISQLDBConn conn)
        {
            if (conn != null)
            {
                try
                {
                    conn.SQLConnection.Disconnect();
                    LogMsg("Disconnected from database server");
                }
                finally
                {
                    conn = null;
                }
            }
        }

        protected void CleanConnection()
        {
            CleanConnection(ref _mainConn);
        }

        #endregion
        #region Logging

        protected void LogMsg(string msg)
        {
            string tmp = GetType().Name + " - " + msg;
            ServiceContainer.Logger.LogMessage(tmp, MsgLevel.Info);
        }

        #endregion

    }
}